package com.demo.idempotent.aspect;

import com.demo.idempotent.annotations.Idempotent;
import com.demo.idempotent.compotent.SimpleRedisLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
@Aspect
@Order(-1)
public class IdempotentAspect {
    @Autowired
    private RedisTemplate redisTemplate;


    @Pointcut("@annotation(com.demo.idempotent.annotations.Idempotent)")
    public void idempotent() {
    }

    @Around("idempotent()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) {
        System.out.println("进入切面");
        Object result = null;
        //获取参数名
        String[] params = ((CodeSignature) joinPoint.getStaticPart().getSignature()).getParameterNames();
        System.out.println("请求参数:" + params);
        //获取参数值
        Object[] args = joinPoint.getArgs();
        System.out.println(IdempotentFlag.isDoing());
        if (!IdempotentFlag.isDoing()) {
            try {
                IdempotentFlag.doing();
                System.out.println(IdempotentFlag.isDoing());
                Map<String, Object> map = new HashMap<>();
                if (params != null) {
                    for (int i = 0; i < params.length; i++) {
                        map.put(params[i], args[i]);
                    }
                }
                Signature signature = joinPoint.getSignature();
                MethodSignature methodSignature = (MethodSignature) signature;
                Method method = methodSignature.getMethod();
                Idempotent idempotent = method.getAnnotation(Idempotent.class);
                //如果添加的有注解
                String key = getIdempotentKey(map, idempotent.express());
                if (StringUtils.isEmpty(idempotent.value()) || StringUtils.isEmpty(key)) {
                    String path = methodSignature.getName();
                    throw new Exception(path + "idempotent config error");
                } else {
                    result = get(joinPoint, idempotent.value(), key);
                }
            } catch (Throwable e) {
                throw new RuntimeException(e);
            } finally {
                IdempotentFlag.done();
            }
        } else {
            try {
                result = joinPoint.proceed(args);
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        }
        return result;

    }

    private String getIdempotentKey(Map<String, Object> map, String express) {
        return "test";
    }


    public Object get(ProceedingJoinPoint joinPoint, String idempotentPackage, String idempotentKey) throws Throwable {
        Object result = null;
        String key = idempotentPackage + ":" + idempotentKey;
        SimpleRedisLock lock = new SimpleRedisLock(redisTemplate, key);
        try {
            if (lock.acquire()) {
                result = joinPoint.proceed(joinPoint.getArgs());
            }
        } catch (Throwable e) {
            throw e;
        } finally {
            lock.release();
        }
        return result;
    }


}
